<script setup lang="ts">
import { useTaskStore, useTimeRangeStore, useWeatherStore } from '@/store';
import { MapMouseEvent, Marker } from 'mapbox-gl';
import { Map as MapboxMap } from 'mapbox-gl';
import LongArrowSvg from 'common/src/assets/imgs/long-arrow.svg?component';
import { CloseBold } from '@element-plus/icons-vue';
import { ElIcon, ElSelect, ElOption } from 'element-plus';
import { formatLon, toLonLatString } from 'common/src/utils/lnglat';
import throttle from 'lodash/throttle';
import { getCustomLocalTimeFormat } from 'common/src/utils/time';
import { getPointPose } from '@/services/task';

interface Props {
  active: boolean;
}

interface AttitudeInfo {
  /** 毫秒时间戳 */
  ts: number;
  lat: number;
  lon: number;
  latLng: string;
  speed: number;
  rollArr: string[];
  pitchArr: string[];
}

const usedSpdOptions = [0, 4, 8, 12, 16, 20];

const props = defineProps<Props>();
const taskStore = useTaskStore();
const weatherStore = useWeatherStore();
const timeRangeStore = useTimeRangeStore();
const spotAttitudePopContent = ref<HTMLDivElement | null>(null);
const spotMarker = ref<Marker | null>(null);
const markerAdded = ref(false);
const currentAnchor = ref<'bottom-left' | 'top-left'>('bottom-left');
const isFlipped = ref(false);
const attitudeInfo = reactive<AttitudeInfo>({
  ts: 0,
  lat: 0,
  lon: 0,
  latLng: '',
  speed: 12,
  rollArr: [],
  pitchArr: [],
});
const loading = ref(false);
const speedOptions = ref([...usedSpdOptions]);

const updateAttitudeThrottle = throttle(async () => {
  loading.value = true;
  const { lon, lat, speed, ts } = attitudeInfo;
  const [lonFormatted] = formatLon(lon);
  try {
    const res = await getPointPose({
      lat, lon: lonFormatted,
      sog: speed, ts: Math.floor(ts / 1000),
    });
    const rollArr: string[] = [], pitchArr: string[] = [];
    res.forEach(item => {
      rollArr.push(typeof item.roll_pred === 'number' ? item.roll_pred.toFixed(2) : '');
      pitchArr.push(typeof item.pitch_pred === 'number' ? item.pitch_pred.toFixed(2) : '');
    });
    Object.assign(attitudeInfo, { rollArr, pitchArr });
  } catch {
    attitudeInfo.rollArr = [];
    attitudeInfo.pitchArr = [];
  } finally {
    loading.value = false;
  }
}, 200, {
  leading: false,
  trailing: true,
});

const handleGetPointAttitude = (e: MapMouseEvent) => {
  const { lng, lat } = e.lngLat || spotMarker.value?.getLngLat();
  // 计算点击/拖拽位置在视窗内的像素 y，用于判断是否需要“倒置显示”
  let pixelY: number | undefined = (e as any)?.point?.y;
  if (pixelY === undefined && weatherStore.map) {
    const proj = (weatherStore.map as MapboxMap).project([lng, lat]);
    pixelY = proj?.y as number;
  }
  const needFlip = typeof pixelY === 'number' && pixelY < 150;
  const wantAnchor: 'bottom-left' | 'top-left' = needFlip ? 'top-left' : 'bottom-left';
  // 同步翻转状态；如锚点不同则重建 Marker
  isFlipped.value = wantAnchor === 'top-left';
  if (wantAnchor !== currentAnchor.value) {
    recreateSpotMarker(wantAnchor);
  }

  attitudeInfo.lat = lat;
  attitudeInfo.lon = lng;
  attitudeInfo.latLng = toLonLatString(lng, lat);
  attitudeInfo.ts = timeRangeStore.currentTime;
  spotMarker.value?.setLngLat([lng, lat]);
  loading.value = true;
  if (['click', 'dragend'].includes(e.type)) {
    updateAttitudeThrottle();
  }
  if (!markerAdded.value) {
    spotMarker.value?.addTo(weatherStore.map as any);
    markerAdded.value = true;
  }
};

const removeSpotMarker = () => {
  spotMarker.value?.remove();
  markerAdded.value = false;
};

const startDecoder = (map: MapboxMap) => {
  map.on('click', handleGetPointAttitude);
};

const endDecoder = (map: MapboxMap) => {
  map.off('click', handleGetPointAttitude);
  spotMarker.value?.remove();
  markerAdded.value = false;
};

const remoteSpeedMethod = (query: string) => {
  const speed = Number(query);
  const filterOptions = usedSpdOptions.filter(opt => String(opt).includes(query));
  if (!Number.isNaN(speed) && speed > 0 && !usedSpdOptions.includes(speed)) {
    speedOptions.value = [speed, ...filterOptions];
  } else {
    speedOptions.value = [...filterOptions];
  }
};

const speedSelectChange = () => {
  if (!usedSpdOptions.includes(attitudeInfo.speed)) {
    usedSpdOptions.unshift(attitudeInfo.speed);
  }
  updateAttitudeThrottle();
  updateAttitudeThrottle.flush();
};

watch(() => timeRangeStore.currentTime, (val) => {
  if (!weatherStore.climateLayerActive && props.active) {
    setTimeout(() => {
      attitudeInfo.ts = val;
      updateAttitudeThrottle();
      updateAttitudeThrottle.flush();
    }, 0);
  }
}, { immediate: true });

watch([
  () => taskStore.infoShow.routePoint,
  () => taskStore.infoShow.regionWxMsg,
  () => taskStore.infoShow.pointDecoder,
], (val) => {
  if (val.some(item => item)) {
    removeSpotMarker();
  }
});

onMounted(() => {
  spotMarker.value = new Marker({
    className: 'marker-popup spot-weather-marker',
    draggable: true,
    element: spotAttitudePopContent.value! as HTMLDivElement,
    anchor: currentAnchor.value,
    offset: [-2, -1],
  });
  // @ts-ignore
  (spotMarker.value as any).on('drag', handleGetPointAttitude);
  (spotMarker.value as any).on('dragend', handleGetPointAttitude);
});

onBeforeUnmount(() => {
  // @ts-ignore
  (spotMarker.value as any).off('drag', handleGetPointAttitude);
  (spotMarker.value as any).off('dragend', handleGetPointAttitude);
});

function recreateSpotMarker(anchor: 'bottom-left' | 'top-left') {
  if (currentAnchor.value === anchor && spotMarker.value) return;
  // 解绑旧事件并移除
  try { (spotMarker.value as any)?.off?.('drag', handleGetPointAttitude); } catch {}
  try { (spotMarker.value as any)?.off?.('dragend', handleGetPointAttitude); } catch {}
  spotMarker.value?.remove();
  markerAdded.value = false;
  // 使用同一个 DOM 元素重新创建 Marker
  spotMarker.value = new Marker({
    className: 'marker-popup spot-weather-marker',
    draggable: true,
    element: spotAttitudePopContent.value! as HTMLDivElement,
    anchor,
    offset: [-2, -1],
  });
  // 重新绑定拖拽事件
  (spotMarker.value as any).on('drag', handleGetPointAttitude);
  (spotMarker.value as any).on('dragend', handleGetPointAttitude);
  currentAnchor.value = anchor;
}

defineExpose({
  startDecoder,
  endDecoder,
});
</script>

<template>
  <div v-show="props.active && markerAdded" class="spot-weather-top">
    <div>时间: {{ getCustomLocalTimeFormat(attitudeInfo.ts, 'YYYY-MM-DD HH:mm') }}</div>
    <div>经纬度: {{ attitudeInfo.latLng }}</div>
    <div class="spd-select">
      <span>船速: </span>
      <ElSelect
        v-model="attitudeInfo.speed"
        size="small"
        style="width: 60px;"
        filterable
        remote
        :remote-method="remoteSpeedMethod"
        @change="speedSelectChange"
      >
        <ElOption
          v-for="opt in speedOptions"
          :key="opt"
          :value="opt"
          :label="opt"
        />
      </ElSelect>kts
    </div>
  </div>
  <div ref="spotAttitudePopContent" class="spot-weather-content" :class="{ 'spot-weather-flipped': isFlipped }">
    <div class="spot-weather-flag spot-attitude-flag" v-loading="loading" element-loading-background="rgba(0, 0, 0, 0.2)">
      <div class="attitude-arrows">
        <LongArrowSvg v-for="(_, idx) in new Array(8).fill(0)" :key="idx" :style="{transform: `rotate(${idx * 45}deg)`}" />
        <span v-for="(_, idx) in new Array(8).fill(0)" :key="`attitude${idx}`" :class="['attitude-text', `attitude-text-${idx}`]">
          <span>{{ attitudeInfo.rollArr[idx] || '--' }}°</span>
          <span>{{ attitudeInfo.pitchArr[idx] || '--' }}°</span>
        </span>
      </div>
      <ElIcon
        class="spot-weather-close"
        @click.stop="() => removeSpotMarker()"
      ><CloseBold /></ElIcon>
    </div>
    <div class="spot-weather-dot" />
  </div>
</template>

<style lang="less" scoped>
.spot-weather-content .spot-weather-flag.spot-attitude-flag {
  padding: 4px;
}
.spd-select {
  display: flex;
  align-items: center;
}
.attitude-arrows {
  position: relative;
  width: 100px;
  height: 100px;
  :is(svg) {
    position: absolute;
    width: 26px;
    height: 26px;
    top: calc(50% - 13px);
    left: calc(50% - 26px);
    transform-origin: right center;
  }
  .attitude-text {
    position: absolute;
    font-size: 12px;
    line-height: 12px;
    display: flex;
    flex-direction: column;
  }
  .attitude-text-0 {
    top: 0;
    left: 50%;
    transform: translateX(-50%);
  }
  .attitude-text-1 {
    top: 0;
    right: 0;
  }
  .attitude-text-2 {
    top: 50%;
    right: 0;
    transform: translateY(-50%);
  }
  .attitude-text-3 {
    bottom: 0;
    right: 0;
  }
  .attitude-text-4 {
    bottom: 0;
    left: 50%;
    transform: translateX(-50%);
  }
  .attitude-text-5 {
    bottom: 0;
    left: 0;
  }
  .attitude-text-6 {
    top: 50%;
    left: 0;
    transform: translateY(-50%);
  }
  .attitude-text-7 {
    top: 0;
    left: 0;
  }
}
/* 提供翻转时可定制的样式钩子（默认不做视觉修改） */
.spot-weather-content.spot-weather-flipped {
  padding-bottom: 0;
  padding-top: 40px;
  .spot-weather-dot {
    bottom: auto !important;
    top: -5px !important;
  }
  .spot-weather-close {
    bottom: 44px !important;
    top: auto !important;
  }
}
</style>
